EinkBro App 的設計概念是讓畫面上的非必要元素愈少愈好。如果某個使用者對於特定功能的使用頻率比較高的話,可以自行將該功能設定到工具列上,或是從設定畫面中,開啟該功能。
多指手勢操作功能,也是在這樣子的設計概念下誕生的功能。對於一般的使用者來說,常用的功能都已經在工具列上。對於更進階的使用者來說,要一直在工具列上點來點去,可能還是會嫌麻煩。因為 EinkBro 的工具列是可以設定在畫面捲動後自動隱藏。對於這類進階的使用者來說,開啟多指手勢操作就是個能增加生產力的作法。
這篇文章中,我會介紹多指手勢操作的實作方式,以及考慮了什麼樣的機制,確保多指操作不會跟網頁 zoom in/out 的手勢有所衝突。
為了偵測觸控事件,首先要實作 View.OnTouchListener
,並覆寫其 onTouch
函式。從它的參數中可以取得一個 MotionEvent
instance。MotionEvent
中包含了這次的觸控事件中,包含了幾個觸控點(pointCount)。以 EinkBro 來說,我們現階段想支援的是雙點觸控的手勢操作,所以我們會特別檢查是不是收到了 2 個點的事件:
在 onTouch 中,我們必須處理 ACTION_POINTER_DOWN
, ACTION_POINTER_UP
和 ACTION_MOVE
。
收到這事件時,要追蹤觸控的啟始點,並且把 inSwipe 設為 true。
when (event.action and MotionEvent.ACTION_MASK) {
MotionEvent.ACTION_POINTER_DOWN -> {
scaleFactor = 1.0f
startPoint0 = event.getPoint(0)
startPoint1 = event.getPoint(1)
inSwipe = true
}
持續追蹤觸控目前的位置。
MotionEvent.ACTION_MOVE -> {
if (inSwipe) {
endPoint0 = event.getPoint(0)
endPoint1 = event.getPoint(1)
}
}
當使用者的手指離開畫面時,我們必須記錄這時的位置,把它跟啟始的位置做比較,再來決定是不是要執行某些功能。
MotionEvent.ACTION_POINTER_UP -> {
if (inSwipe) {
val offSetX = endPoint1.x - startPoint1.x
val offSetY = endPoint1.y - startPoint1.y
//Log.i("SWIPE", "offsetX: $offSetX, offsetY: $offSetY")
if (isValidSwipe(offSetX, offSetY)) {
if (abs(offSetX) > abs(offSetY)) {
if (isSameXDirection()) {
if (offSetX > 0) onSwipeRight() else onSwipeLeft()
}
} else {
if (isSameYDirection()) {
if (offSetY > 0) onSwipeBottom() else onSwipeTop()
}
}
}
inSwipe = false
}
}
isValidSwipe()
會被用來判斷手指移動的距離是不是有大於預設的 threshold,有超過的話,才會接著再判斷它是屬於朝著 up/down/left/right 的哪個方向移動,然後呼叫對應的功能。
private fun isValidSwipe(offSetX: Int, offSetY: Int) =
max(abs(offSetX), abs(offSetY)) > SWIPE_THRESHOLD && !isScaling()
private fun isSameXDirection(): Boolean {
val point0Diff = endPoint0.x - startPoint0.x
val point1Diff = endPoint1.x - startPoint1.x
return (point0Diff > 0 && point1Diff > 0) || (point0Diff < 0 && point1Diff < 0)
}
private fun isSameYDirection(): Boolean {
val point0Diff = endPoint0.y - startPoint0.y
val point1Diff = endPoint1.y - startPoint1.y
return (point0Diff > 0 && point1Diff > 0) || (point0Diff < 0 && point1Diff < 0)
}
有了上面這些實作,多指觸控的功能便完成了。這樣是不是就從此過著幸福快樂的日子了呢?當然不是,哪有那麼好的事。
在使用一段時間以後,發現到如果網頁中有一些圖片,原先是有支援縮放的功能,在開啟多指手勢操作後,它就失效了!這時才想到,縮放畫面其實也是會利用到兩根手指,如果沒有特別處理的話,這兩個功能是會打架的。所以,我們還需要實作讓這兩種手勢可以區分開來的邏輯判斷才行。下一篇文章將會說明這部分的處理。